package handler

import (
	"context"
	"fmt"
	"gitee.com/DonHz/electronic-business-systems/mxshop_srvs/order_srv/global"
	"gitee.com/DonHz/electronic-business-systems/mxshop_srvs/order_srv/model"
	"gitee.com/DonHz/electronic-business-systems/mxshop_srvs/order_srv/proto"
	"golang.org/x/exp/rand"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"time"
)

type OrderServer struct {
	proto.UnimplementedOrderServer
}

func (s *OrderServer) CartItemList(ctx context.Context, req *proto.UserInfo) (*proto.CartItemListResponse, error) {
	var shopCarts []model.ShoppingCart
	var resp proto.CartItemListResponse
	if res := global.DB.Where(&model.ShoppingCart{User: req.Id}).Find(&shopCarts); res.Error != nil {
		return nil, res.Error
	} else {
		resp.Total = res.RowsAffected
	}
	for _, shopCart := range shopCarts {
		resp.Data = append(resp.Data, &proto.ShopCartInfoResponse{
			Id:      shopCart.ID,
			UserId:  shopCart.User,
			GoodsId: shopCart.Goods,
			Nums:    shopCart.Nums,
			Checked: shopCart.Checked,
		})
	}
	return &resp, nil
}
func (s *OrderServer) CreateCartItem(ctx context.Context, req *proto.CartItemRequest) (*proto.ShopCartInfoResponse, error) {
	var shopCart model.ShoppingCart
	if res := global.DB.Where(&model.ShoppingCart{Goods: req.GoodsId, User: req.UserId}).First(&shopCart); res.RowsAffected == 1 {
		// 更新
		shopCart.Nums += req.Nums
	} else {
		// 插入
		shopCart.User = req.UserId
		shopCart.Goods = req.GoodsId
		shopCart.Nums = req.Nums
		shopCart.Checked = false
	}
	global.DB.Save(&shopCart)
	return &proto.ShopCartInfoResponse{
		Id:      shopCart.ID,
		UserId:  shopCart.User,
		GoodsId: shopCart.Goods,
		Nums:    shopCart.Nums,
		Checked: shopCart.Checked,
	}, nil
}
func (s *OrderServer) UpdateCartItem(ctx context.Context, req *proto.CartItemRequest) (*emptypb.Empty, error) {
	var shopCart model.ShoppingCart
	if res := global.DB.Where("goods=? and user=?", req.GoodsId, req.UserId).First(&shopCart); res.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "购物车记录不存在")
	}
	shopCart.Checked = req.Checked
	if req.Nums > 0 {
		shopCart.Nums = req.Nums
	}
	global.DB.Save(&shopCart)
	return &emptypb.Empty{}, nil
}
func (s *OrderServer) DeleteCartItem(ctx context.Context, req *proto.CartItemRequest) (*emptypb.Empty, error) {

	if res := global.DB.Where("goods=? and user=?", req.GoodsId, req.UserId).Delete(&model.ShoppingCart{}); res.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "购物车记录不存在")
	}
	return &emptypb.Empty{}, nil
}

func (s *OrderServer) CreateOrder(ctx context.Context, req *proto.OrderRequest) (*proto.OrderInfoResponse, error) {
	var goodsIds []int64
	var shopCarts []model.ShoppingCart
	var goodsNumsMap = make(map[int64]int64)
	if res := global.DB.Where(&model.ShoppingCart{User: req.UserId, Checked: true}).Find(&shopCarts); res.RowsAffected == 0 {
		return nil, status.Error(codes.InvalidArgument, "没有选中商品结算")
	}
	for _, shopCart := range shopCarts {
		goodsIds = append(goodsIds, shopCart.Goods)
		goodsNumsMap[shopCart.Goods] = shopCart.Nums
	}

	// 跨服务调用
	// 商品微服务 库存微服务
	goods, err := global.GoodsSrvClient.BatchGetGoods(context.Background(), &proto.BatchGoodsIdInfo{
		Id: goodsIds,
	})
	if err != nil {
		return nil, status.Error(codes.InvalidArgument, "批量查询商品信息失败, "+err.Error())
	}
	var orderAmount float32
	var orderGoods []*model.OrderGoods
	var goodsInvInfo []*proto.GoodsInvInfo
	for _, good := range goods.Data {
		orderAmount += good.ShopPrice * float32(goodsNumsMap[good.Id])
		orderGoods = append(orderGoods, &model.OrderGoods{
			Goods:      good.Id,
			GoodsName:  good.Name,
			GoodsImage: good.GoodsFrontImage,
			GoodsPrice: good.ShopPrice,
			Nums:       goodsNumsMap[good.Id],
		})
		goodsInvInfo = append(goodsInvInfo, &proto.GoodsInvInfo{
			GoodsId: good.Id,
			Num:     goodsNumsMap[good.Id],
		})
	}
	// 库存扣减
	if _, err = global.InventorySrvClient.Sell(context.Background(), &proto.SellInfo{
		GoodsInfo: goodsInvInfo,
	}); err != nil {
		return nil, status.Error(codes.ResourceExhausted, "库存扣减失败")
	}
	// 生成订单
	tx := global.DB.Begin()
	order := model.OrderInfo{
		User:         req.UserId,
		OrderMount:   orderAmount,
		OrderSn:      GenerateOrderSn(req.UserId),
		Address:      req.Address,
		SignerName:   req.Name,
		SingerMobile: req.Mobile,
		Post:         req.Post,
	}
	if res := tx.Save(&order); res.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Error(codes.Internal, "生成订单失败")
	}
	for _, orderGood := range orderGoods {
		orderGood.Order = order.ID
	}
	// 批量插入
	if res := tx.CreateInBatches(&orderGoods, 100); res.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Error(codes.Internal, "批量插入订单商品失败")
	}
	// 清空购物车
	if res := tx.Where(&model.ShoppingCart{User: req.UserId, Checked: true}).Delete(&model.ShoppingCart{}); res.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Error(codes.Internal, "清空购物车失败")
	}
	tx.Commit()
	return &proto.OrderInfoResponse{
		Id:      order.ID,
		UserId:  order.User,
		OrderSn: order.OrderSn,
		PayType: order.PayType,
		Status:  order.Status,
		Post:    order.Post,
		Total:   order.OrderMount,
		Address: order.Address,
		Name:    order.SignerName,
		Mobile:  order.SingerMobile,
		AddTime: order.CreatedAt.Format("2006-01-02 15:04:05"),
	}, nil
}
func (s *OrderServer) OrderList(ctx context.Context, req *proto.OrderFilterRequest) (*proto.OrderListResponse, error) {
	var orders []model.OrderInfo
	var resp proto.OrderListResponse
	var total int64
	global.DB.Model(&model.OrderInfo{}).Where("user=?", req.UserId).Count(&total)
	resp.Total = total

	global.DB.Scopes(Paginate(int(req.Pages), int(req.PagePerNums))).Where(&model.OrderInfo{User: req.UserId}).Find(&orders)
	for _, order := range orders {
		resp.Data = append(resp.Data, &proto.OrderInfoResponse{
			Id:      order.ID,
			UserId:  order.User,
			OrderSn: order.OrderSn,
			PayType: order.PayType,
			Status:  order.Status,
			Post:    order.Post,
			Total:   order.OrderMount,
			Address: order.Address,
			Name:    order.SignerName,
			Mobile:  order.SingerMobile,
			AddTime: order.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}
	return &resp, nil
}
func (s *OrderServer) OrderDetail(ctx context.Context, req *proto.OrderRequest) (*proto.OrderInfoDetailResponse, error) {
	var order model.OrderInfo
	var resp proto.OrderInfoDetailResponse
	if res := global.DB.Where(&model.OrderInfo{BaseModel: model.BaseModel{ID: req.Id}, User: req.UserId}).First(&order); res.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "订单不存在")
	}
	resp.OrderInfo = &proto.OrderInfoResponse{
		Id:      order.ID,
		UserId:  order.User,
		OrderSn: order.OrderSn,
		PayType: order.PayType,
		Status:  order.Status,
		Post:    order.Post,
		Total:   order.OrderMount,
		Address: order.Address,
		Name:    order.SignerName,
		Mobile:  order.SingerMobile,
		AddTime: order.CreatedAt.Format("2006-01-02 15:04:05"),
	}
	// 订单商品信息
	var orderGoods []model.OrderGoods
	global.DB.Where(&model.OrderGoods{Order: order.ID}).Find(&orderGoods)
	for _, orderGood := range orderGoods {
		resp.Goods = append(resp.Goods, &proto.OrderItemResponse{
			GoodsId:    int64(orderGood.Goods),
			GoodsName:  orderGood.GoodsName,
			GoodsImage: orderGood.GoodsImage,
			GoodsPrice: orderGood.GoodsPrice,
			Nums:       int64(orderGood.Nums),
		})
	}
	return &resp, nil
}
func (s *OrderServer) UpdateOrderStatus(ctx context.Context, req *proto.OrderStatus) (*emptypb.Empty, error) {
	res := global.DB.Model(&model.OrderInfo{}).Where("order_sn = ?", req.OrderSn).Update("status", req.Status)
	if res.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "订单不存在")
	}
	return &emptypb.Empty{}, nil
}

func GenerateOrderSn(userId int64) string {
	now := time.Now()
	rand.Seed(uint64(time.Now().UnixNano()))
	// 年月日时分秒+用户id+2位随机数
	orderSn := fmt.Sprintf("%d%d%d%d%d%d%d%d",
		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Nanosecond(),
		userId, rand.Intn(90)+10,
	)
	return orderSn
}
